package utils;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import model.Domain;
import model.Response;
import model.Resticket;
import model.Resticket_;
import model.Techticket;
import model.Techticket_;
import model.User;
import dtos.ResticketDTO;
import dtos.TechticketDTO;
import dtos.UserDTO;

/**
 * Session Bean implementation class ResticketDAO
 * 
 * @author Radulescu Cristina
 * @author Pop Loredana
 */
@Stateless
@LocalBean
public class ResticketDAO implements ResticketDAORemote {
	@PersistenceContext
	EntityManager em;

	@EJB
	Conv conv;

	/**
	 * Default constructor.
	 */

	public ResticketDAO() {
		// TODO Auto-generated constructor stub
	}

	/**
	 * Method used to insert ticket
	 * 
	 * @param ticket
	 */
	public void insertResticket(ResticketDTO ticket) {
		Resticket t = em.find(Resticket.class, ticket.getId());
		if (t == null) {
			Resticket t1 = conv.fromEntityResticketDTO(ticket);
			em.persist(t1);
		} else {
			t.setResponse(em.find(Response.class, ticket.getId()));
			em.merge(t);
		}
	}

	/**
	 * Method used to get a resticket by id
	 * 
	 * @param id
	 * @return resticket
	 */
	@Override
	public ResticketDTO getResticket(int id) {
		return conv.fromEntityResticket(em.find(Resticket.class, id));
	}

	/**
	 * Method used to update resticket
	 * 
	 * @param ticket
	 *            of type resticket
	 */
	@Override
	public void updateResticket(ResticketDTO ticket) {
		Resticket t = em.find(Resticket.class, ticket.getId());
		if (t == null) {
			Resticket t1 = conv.fromEntityResticketDTO(ticket);
			em.persist(t1);
		} else {
			t.setStatus(ticket.getStatus());
			t.setResponse(em.find(Response.class, ticket.getIdResponse()));
			em.merge(t);
		}

	}

	/**
	 * Method used to get all restickets
	 * 
	 * @return list of restickets
	 */
	@Override
	public List<ResticketDTO> getAllRestickets() {
		List<ResticketDTO> resultTicketsList = new ArrayList<>();
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Resticket> cq = cb.createQuery(Resticket.class);
		Root<Resticket> ticket = cq.from(Resticket.class);
		cq.select(ticket).orderBy(cb.desc(ticket.get("status")))
				.orderBy(cb.desc(ticket.get("status")));

		TypedQuery<Resticket> q = em.createQuery(cq);

		List<Resticket> tickets = q.getResultList();
		for (Resticket u : tickets) {
			if (u.getStatus().equals("Pending")
					|| (u.getStatus().equals("Accepted")))
				resultTicketsList.add(conv.fromEntityResticket(u));
		}
		return resultTicketsList;
	}

	/**
	 * Method used to get all restickets by user id from current month
	 * 
	 * @param user
	 */
	@Override
	public List<ResticketDTO> getResticketsByUserIdCurrentMonth(UserDTO ud) {
		User u = conv.fromEntityUserDTO(ud);

		Calendar cal = Calendar.getInstance();
		Date date = new Date();
		cal.setTime(date);
		cal.add(Calendar.MONTH, -1);

		List<ResticketDTO> resultTicketsList = new ArrayList<>();

		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Resticket> cq = cb.createQuery(Resticket.class);
		Root<Resticket> ticket = cq.from(Resticket.class);
		cq.select(ticket);
		cq.orderBy(cb.desc(ticket.get(Resticket_.date))).orderBy(
				cb.desc(ticket.get(Resticket_.id)));
		TypedQuery<Resticket> q = em.createQuery(cq);

		List<Resticket> tickets = q.getResultList();
		for (Resticket t : tickets) {
			Calendar cal2 = Calendar.getInstance();
			cal2.setTime(t.getDate());
			if (t.getUser().getId() == u.getId() && cal.before(cal2)) {
				resultTicketsList.add(conv.fromEntityResticket(t));
			}
		}

		return resultTicketsList;
	}

	/**
	 * Method used to delete resticket
	 * 
	 * @param resticket
	 */
	@Override
	public void deleteResticket(ResticketDTO ud) {
		Resticket r = em.find(Resticket.class, ud.getId());
		em.createQuery("delete from Resticket where id=:id")
				.setParameter("id", r.getId()).executeUpdate();
	}

	/**
	 * Method used to get Restickets by domain
	 * 
	 * @param user
	 * @return list of restickets
	 */
	@Override
	public List<ResticketDTO> getResticketsByUserDomain(UserDTO user) {
		int idUserDomain = user.getIdDomain();
		Domain dom = em.find(Domain.class, idUserDomain);
		System.out.println("id domeniu " + dom.getId());

		List<ResticketDTO> tickets = new ArrayList<>();

		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Resticket> cq = cb.createQuery(Resticket.class);
		Root<Resticket> resources = cq.from(Resticket.class);
		cq.select(resources);

		cq.orderBy(cb.desc(resources.get(Resticket_.status))).orderBy(
				cb.desc(resources.get(Resticket_.id)));
		List<Resticket> ticketList = em.createQuery(cq).getResultList();
		for (Resticket t : ticketList) {
			User u = t.getUser();
			Domain d = u.getDomain();
			if (d.getId() == dom.getId()
					&& (t.getStatus().equals("Pending") || (t.getStatus()
							.equals("Processed")))) {
				tickets.add(conv.fromEntityResticket(t));
			}
		}
		return tickets;
	}

	/**
	 * Method used to get restickets by user
	 * 
	 * @param user
	 * @return list of restickets
	 */
	@Override
	public List<ResticketDTO> getResticketsByUser(UserDTO user) {
		List<ResticketDTO> tickets = new ArrayList<>();

		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Resticket> cq = cb.createQuery(Resticket.class);
		Root<Resticket> resources = cq.from(Resticket.class);
		cq.select(resources);

		cq.orderBy(cb.desc(resources.get(Resticket_.status)));
		List<Resticket> ticketList = em.createQuery(cq).getResultList();
		for (Resticket t : ticketList) {
			User u = t.getUser();
			if (u.getId() == user.getId()) {
				tickets.add(conv.fromEntityResticket(t));
			}
		}
		return tickets;
	}

	/**
	 * Method used to get all restickets assigned to inactive Office manager
	 * 
	 * @return list of restickets
	 */
	@Override
	public List<ResticketDTO> getResticketsByReplacerAdmin() {
		List<ResticketDTO> tickets = new ArrayList<>();

		// get all domains where the Office Manager is replaced by Admin
		List<Domain> inactOMDomain = new ArrayList<>();

		CriteriaBuilder cbUser = em.getCriteriaBuilder();
		CriteriaQuery<User> cqUser = cbUser.createQuery(User.class);
		Root<User> user = cqUser.from(User.class);
		cqUser.select(user);
		TypedQuery<User> q = em.createQuery(cqUser);

		List<User> users = q.getResultList();

		for (User u : users) {
			User replacementUser = u.getUser();
			if (u.getIsactive() == 0 && replacementUser != null
					&& replacementUser.getUsertype().getId() == 1) {
				inactOMDomain.add(u.getDomain());
			}
		}

		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Resticket> cq = cb.createQuery(Resticket.class);
		Root<Resticket> resources = cq.from(Resticket.class);
		cq.select(resources);

		cq.orderBy(cb.desc(resources.get(Resticket_.status)));
		List<Resticket> ticketList = em.createQuery(cq).getResultList();
		for (Resticket t : ticketList) {
			Domain dom = t.getUser().getDomain();

			for (Domain d : inactOMDomain) {
				if (d.getId() == dom.getId()) {
					tickets.add(conv.fromEntityResticket(t));
				}
			}
		}
		return tickets;
	}

	/**
	 * Method used to order restickets by id and status
	 * 
	 * @return list of techtickets
	 */
	@Override
	public List<ResticketDTO> getAllResticketsOrderedByIdAndStatus() {
		List<ResticketDTO> resultTicketsList = new ArrayList<>();
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Resticket> cq = cb.createQuery(Resticket.class);
		Root<Resticket> ticket = cq.from(Resticket.class);
		cq.select(ticket).orderBy(cb.desc(ticket.get("status")))
				.orderBy(cb.desc(ticket.get("id")));

		TypedQuery<Resticket> q = em.createQuery(cq);
		List<Resticket> tickets = q.getResultList();
		for (Resticket u : tickets) {
			resultTicketsList.add(conv.fromEntityResticket(u));
		}
		return resultTicketsList;
	}
}
